<?php


namespace App\Services\Game;


use App\DTOS\IPayNowOrderDTO;
use App\DTOS\NeiGouDTO;
use App\Exceptions\ServiceException;
use App\IpayNow\Config\Config;
use App\IpayNow\Util\PostRequest;
use App\IpayNow\Util\SignaTure;
use App\Models\Game\GameGoods;
use App\Models\Game\PayOrder;
use App\Models\Game\Server;
use App\Utils\MyLog;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class IPayNowService
{

    private NeigouService $NeigouService;

    /**
     * IPayNowService constructor.
     * @param NeigouService $NeigouService
     */
    public function __construct(NeigouService $NeigouService)
    {
        $this->NeigouService = $NeigouService;
    }

    /**
     * @param IPayNowOrderDTO $orderDTO
     * @return string url|base64 #返回结果
     * @throws \Exception
     */
    public function createOrder(IPayNowOrderDTO $orderDTO){
        $goodsId = $orderDTO->getGoodsId();
        $number = $orderDTO->getNumber();
        $priceFee = $orderDTO->getPriceFee();
        $roleId = $orderDTO->getRoleId();
        $serverId = $orderDTO->getServerId();
        $outputType = "".$orderDTO->getOutputType();
        $gameGoods = GameGoods::query()->where('id',$goodsId)->first();
        if (!$gameGoods) {
            throw new \Exception('此商品不存在');
        }
        $server = Server::query()->where('server_id',$serverId)->first();
        if (!$server){
            throw new \Exception('此服务器不存在');
        }
        $status = data_get($server,'status');
        if ($status!=1){ //未开服
            throw new \Exception('当前服务器未开服');
        }
        $orderNo = 'xz2_'. getSnowFlakeId();

        $requestbody = [];
        $requestbody["funcode"]           = Config::TRADE_FUNCODE;
        $requestbody["version"]           = "1.0.0";
        $requestbody["appId"]             = Config::$AppId;
        $requestbody["mhtOrderNo"]        = $orderNo;
        $requestbody["mhtOrderName"]      = $gameGoods->name;
        $requestbody["mhtCurrencyType"]   = Config::TRADE_CURRENCYTYPE;
        $requestbody["mhtOrderAmt"]       = (int)($gameGoods->price_fee * $number); //订单金额,分
        $requestbody["mhtOrderDetail"]    = $gameGoods->detail;
        $requestbody["mhtOrderTimeOut"]   = Config::$trade_time_out;
        $requestbody["mhtOrderStartTime"] = date("YmdHis");
        $requestbody["notifyUrl"]         = Config::$back_notify_url;
        $requestbody["mhtCharset"]        = Config::TRADE_CHARSET;
        $requestbody["outputType"]        = $outputType; //  0返回二维码, 1 返回链接

        $requestbody["deviceType"]        = Config::TRADE_DEVICE_TYPE;
        $requestbody["mhtLimitPay"]       =  "0";//不限制卡类型
        $requestbody["mhtOrderType"]      = Config::TRADE_TYPE;
        $requestbody["mhtSignType"]       = Config::TRADE_SIGN_TYPE;


        foreach($requestbody as &$value) {
            if (is_null($value)) $value = 'empty';
        }

        $info = new SignaTure();
        $req_str = $info -> getToStr($requestbody, Config::$Key);
        $post = new PostRequest();
        $res = $post -> post(Config::TRADE_URL, $req_str);
        $code = (bool)stripos($res, '&tn=');
        if($code) { //下单成功

            //记录到订单表 begin
            PayOrder::query()->insert([
                'order_no'=>$orderNo,
                'name'=>$gameGoods->name,
                'detail'=>$gameGoods->detail,
                'status'=>0,
                'game_area'=>$serverId,
                'front_fee'=>$priceFee,
                'fee'=>$gameGoods->price_fee,
                'role_id'=>$roleId,
                'goods_id'=>$goodsId,
                'number'=>$number,
                'created_at'=>date("Y-m-d H:i:s"),
            ]);
            //记录到订单表 end

            $arr = explode('&', $res);
            $gettn = '';
            foreach ($arr as $v) {
                $tn = explode('=', $v);
                if ($tn[0] == 'tn') {
                    $gettn = $tn[1];
                }
            }
            return urldecode($gettn);
        } else {
            throw new \Exception("ipay now 2 create order error");
        }
    }

    /**
     * 验证签名
     * @param string $params
     * @param string $appKey
     */
    private function verifySign($params='', $appKey=''){
        if($params != '') {
            $arr = explode('&', $params);
            $nowArr = array();
            foreach($arr as $v) {
                $kv = explode('=', $v);
                $nowArr[$kv[0]] = $kv[1];
            }
            ksort($nowArr);
            $newstr = '';
            foreach($nowArr as $key => $value) {
                if($value == '' || $key == 'signature') {
                    continue;
                }
                $newstr .= $key.'='.urldecode($value).'&';
            }
            $newstr .= md5($appKey);

            if( $nowArr['signature'] == md5($newstr) ) {
                return true;
            } else {
                return false;
            }
        }
    }


    /**
     * @param string $params
     * @return string  success=Y | success=N
     */
    public function payCallback($params=''){ //支付回调通知

        $code = $this->verifySign($params, Config::$Key);
        if (!$code){
            MyLog::info("验签失败:" . $params);
            return 'success=N';
        }
        $data = urlencodedStrToArray($params);
        $channelOrderNo = data_get($data,'channelOrderNo');
        $mhtOrderNo = data_get($data,'mhtOrderNo');
        $payOrder = PayOrder::query()->where('order_no',$mhtOrderNo)->first();
        $payOrder->lockForUpdate();
        $goodsId = data_get($payOrder,'goods_id');
        $gameGoods = GameGoods::query()->find($goodsId);
        $typeValue = data_get($gameGoods,'type_value');
        DB::beginTransaction();
        try{
            if (!$payOrder){
                return 'success=Y'; //解决报错
            }
            if ($payOrder->status == 1){
                return 'success=Y';
            }
            $payOrder->updated_at = date("Y-m-d H:i:s");
            $payOrder->status = 1;
            $payOrder->channel_order_no = $channelOrderNo;
            $payOrder->save();
            $neiGouDTO = new NeiGouDTO();
            $neiGouDTO->setGameArea($payOrder->game_area);
            $neiGouDTO->setNumber($payOrder->number);
            $neiGouDTO->setRoleId($payOrder->role_id);
            $neiGouDTO->setOrderNo($payOrder->order_no);
            $neiGouDTO->setGoodsId($payOrder->goods_id);
            $neiGouDTO->setTypeValue($typeValue);
            try {
                $this->NeigouService->pushToServer($neiGouDTO);
                $payOrder->updated_at = date("Y-m-d H:i:s");
                $payOrder->push_status = 1;
                $payOrder->save();
            } catch (ServiceException $e) {
                $payOrder->updated_at = date("Y-m-d H:i:s");
                $payOrder->push_status = -1;
                $payOrder->save();
            }
            DB::commit();
            return 'success=Y';
        } catch(\Exception $e){
            DB::rollBack();
            Log::error( "回调失败: " . $e->getMessage());
            return 'success=N';
        }
    }



}
